package main;

import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.concurrent.TimeoutException;

import util.Utilities;

public class AdbCommands {
	private final String ADB_WINDOWS = "adb.exe";// "cmd /c adb.exe";
	private final String ADB_LINUX = "./adb";

	private final String AAPT_WINDOWS = "aapt.exe";// "cmd /c aapt.exe";
	private final String AAPT_LINUX = "./aapt";
	// aapt dump badging <path-to-apk>

	private final String CMD_ROOT = "root"; // INICIAR COMO ROOT
	private final String CMD_SHELL = "shell";
	private final String CMD_LIST_DEVICES = "devices";
	private final String CMD_CONNECT_IP = "connect";// +ip+port?�
	private final String CMD_DISCONNECT_IP = "disconnect";
	private final String CMD_CONNECT_USB = "usb";
	private final String CMD_START_SERVER = "start-server";
	private final String CMD_KILL_SERVER = "kill-server";
	private final String CMD_PULL = "pull";
	private final String CMD_PUSH = "push";
	private final String CMD_INSTALL = "install";
	private final String CMD_LIST_PACKAGES = "pm list packages -f";
	private final String CMD_LS = "ls";

	private final String CMD_AAPT_DUMP_BADGING = "dump badging";

	private final int WINDOWS = 0;
	private final int LINUX = 1;

	// private int os = new identifyOS().identifyOS();
	private String ADB = "";
	private String AAPT = "";

	public AdbCommands(String deviceSerial) throws Exception {
		switch (new identifyOS().identifyOS()) {
		case WINDOWS:
			ADB = ADB_WINDOWS;
			AAPT = AAPT_WINDOWS;
			break;
		case LINUX:
			ADB = ADB_LINUX;
			AAPT = AAPT_LINUX;
			break;
		default:
			throw new Exception("ERROR OS NOT SUPPORTED!!! tell me ;)");
		}
		if (deviceSerial != null) {
			if (deviceSerial.length() > 0) {
				ADB = ADB + " -s " + deviceSerial;
			}
		}
	}

	boolean startAdbServer() {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_KILL_SERVER;
		if (cmd.launchCommand(command, null)) {
			if (new identifyOS().identifyOS() == 0) {
				command = ADB + " " + CMD_START_SERVER;
				if (!cmd.launchCommand(command, null)) {
					return false;
				}
			}
		} else {
			return false;
		}
		return true;
	}

	boolean connectAdb(boolean useNetAdb, String IP) {
		commandLine cmd = new commandLine();
		String command = "";
		// if (cmd.launchCommand(command)) {
		if (!useNetAdb) {
			command = ADB + " " + CMD_CONNECT_USB;
			if (cmd.launchCommand(command, null)) {
				return true;
			}
		} else {
			command = ADB + " " + CMD_CONNECT_IP + " " + IP;
			Vector<String> out = new Vector<String>();
			if (cmd.launchCommand(command, out)) {
				for (int i = 0; i < out.size(); i++) {
					if (out.get(i).indexOf("unable to connect") >= 0) {
						return false;
					}
				}
				return true;
			}
		}
		// }
		return false;
	}

	boolean useRoot() {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_ROOT;
		if (cmd.launchCommand(command, null)) {
			// command = ADB + " " + CMD_CONNECT_IP + " " + IP;
			// if (cmd.launchCommand(command)) {
			return true;
			// }
		}
		return false;
	}

	boolean disconnectAdb(boolean restartAdb) {// , boolean useNetAdb, String
												// IP) {
		// test if there is any device connected through IP to desconnect it
		Vector<String> outString = new Vector<String>();
		listDevices(outString);

		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_KILL_SERVER;

		for (int i = 0; i < outString.size(); i++) {
			int endIndex = outString.get(i).indexOf(":");
			if (endIndex > 0) {
				if (new Utilities().ValidateIPAddress(outString.get(i)
						.substring(0, endIndex))) {
					command = ADB + " " + CMD_DISCONNECT_IP + " "
							+ outString.get(i).substring(0, endIndex);
					if (!cmd.launchCommand(command, null)) {
						// return false;
					}
				}
			}
		}

		command = ADB + " " + CMD_KILL_SERVER;
		if (cmd.launchCommand(command, null)) {
			return true;
		}
		return false;
	}

	boolean listDataData(Vector<String> out) {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_SHELL + " ls /data/data/";
		if (cmd.launchCommand(command, out)) {
			return true;
		}
		return false;
	}

	boolean listUserApk(Vector<AppApk> out) {
		commandLine cmd = new commandLine();
		String path = "/data/app/";
		String command = ADB + " " + CMD_SHELL + " ls " + path;
		if (cmd.launchCommandApk(command, out, path)) {
			return true;
		}
		return false;
	}

	boolean listSystemApk(Vector<AppApk> out) {
		commandLine cmd = new commandLine();
		String path = "/system/app/";
		String command = ADB + " " + CMD_SHELL + " ls " + path;
		if (cmd.launchCommandApk(command, out, path)) {
			return true;
		}
		return false;
	}

	/**
	 * Download file from phone
	 * 
	 * @param from
	 *            Name of the remote file or directory to download
	 * @param to
	 *            Name of the local file or directory
	 * @param timeOut
	 * @return
	 */
	boolean pullFile(String from, String to, long timeOut) {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_PULL + " " + from + " " + to;
		Vector<String> out = new Vector<String>();
		if (cmd.launchCommand(command, out)) {
			return true;
		}
		return false;
	}

	/**
	 * Upload file to phone
	 * 
	 * @param from
	 *            Name of the local file or directory to upload
	 * @param to
	 *            Name of the remote file or directory
	 * @param timeOut
	 * @return
	 */
	boolean pushFile(String from, String to, long timeOut) {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_PUSH + " " + from + " " + to;
		// if (cmd.launchCommand(command)) {
		Vector<String> out = new Vector<String>();
		if (cmd.launchCommand(command, out)) {
			return true;
		}
		/*
		 * try { if (cmd.executeCommandLine(command, true, true, timeOut) == 0)
		 * { return true; } } catch (IOException e) { // TODO Auto-generated
		 * catch block e.printStackTrace(); } catch (InterruptedException e) {
		 * // TODO Auto-generated catch block e.printStackTrace(); } catch
		 * (TimeoutException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); }
		 */
		return false;
	}

	boolean installApk(String path, String name, boolean keepData,
			boolean toSD, long timeOut) {
		commandLine cmd = new commandLine();
		String INSTALL = CMD_INSTALL;
		if (keepData) {
			INSTALL = INSTALL + " -r";
		}
		if (toSD) {
			INSTALL = INSTALL + " -s";
		}
		String command = ADB + " " + INSTALL + " " + path + name;
		// if (cmd.launchCommand(command)) {
		Vector<String> out = new Vector<String>();
		if (cmd.launchCommand(command, out)) {
			return true;
		}
		/*
		 * try { if (cmd.executeCommandLine(command, true, true, timeOut) == 0)
		 * { return true; } } catch (IOException e) { // TODO Auto-generated
		 * catch block e.printStackTrace(); } catch (InterruptedException e) {
		 * // TODO Auto-generated catch block e.printStackTrace(); } catch
		 * (TimeoutException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); }
		 */
		return false;
	}

	boolean getApkInformation(String path, Vector<String> out) {
		// aapt dump badging data/app/net.canaryx.gpsaids-1.apk
		commandLine cmd = new commandLine();
		String command = AAPT + " " + CMD_AAPT_DUMP_BADGING + " " + path;
		if (cmd.launchCommand(command, out)) {
			return true;
		}
		return false;
	}

	/**
	 * Test if the required program adb exist
	 * 
	 * @return <code>true</code> if exist
	 */
	boolean isAdb() {
		File adb = null;
		switch (new identifyOS().identifyOS()) {
		case WINDOWS:
			adb = new File("adb.exe");
			break;
		case LINUX:
			adb = new File("adb");
			break;
		default:
			break;
		}
		if (adb == null) {
			return false;
		}
		return adb.exists();
	}

	/**
	 * Test if the required program aapt exist
	 * 
	 * @return <code>true</code> if exist
	 */
	boolean isAapt() {
		File aapt = null;
		switch (new identifyOS().identifyOS()) {
		case WINDOWS:
			aapt = new File("aapt.exe");
			break;
		case LINUX:
			aapt = new File("aapt");
			break;
		default:
			break;
		}
		if (aapt == null) {
			return false;
		}
		return aapt.exists();
	}

	boolean listAllPackages(Vector<AppApk> out) {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_SHELL + " " + CMD_LIST_PACKAGES;
		Vector<String> outString = new Vector<String>();
		try {
			if (cmd.launchCommand(command, outString, 2000)) {
				for (int i = 0; i < outString.size(); i++) {
					if (outString.get(i).startsWith("package:")
							&& (!outString.get(i).contains("framework"))) {
						int firstIndex = -1;
						int lastIndex = -1;
						firstIndex = outString.get(i).indexOf("/");
						lastIndex = outString.get(i).lastIndexOf("/") + 1;
						String path = outString.get(i).substring(firstIndex,
								lastIndex);
						System.out.println(path);
						firstIndex = lastIndex;
						lastIndex = outString.get(i).lastIndexOf("=");
						String apkFile = outString.get(i).substring(firstIndex,
								lastIndex);
						System.out.println(apkFile);
						firstIndex = lastIndex + 1;
						lastIndex = outString.get(i).length();
						String packageName = outString.get(i).substring(
								firstIndex, lastIndex);
						System.out.println(packageName);
						AppApk apk = new AppApk(path, packageName, apkFile);
						out.add(apk);
					}
				}
				return true;
			}
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			System.err.println("Error: list packages");
		}
		return false;
	}

	boolean listDevices(Vector<String> outString) {
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_LIST_DEVICES;
		if (cmd.launchCommand(command, outString)) {
			for (int i = 0; i < outString.size(); i++) {
				int lastIndex = outString.get(i).indexOf("device") - 1;
				outString.set(i, outString.get(i).substring(0, lastIndex));
				System.out.println(outString.get(i));
			}
			return true;
		}
		return false;
	}

	boolean fileExist(String path, String file) {
		String errorString = "No such file or directory";
		commandLine cmd = new commandLine();
		String command = ADB + " " + CMD_LS + " " + path;
		Vector<String> out = new Vector<String>();
		if (cmd.launchCommand(command, out)) {
			String found = findString(out, file);
			if (!found.equalsIgnoreCase("")) {
				return true;
			}
		}
		System.out.println(errorString);
		return false;
	}

	private String findString(Vector<String> out, String name) {
		Vector<String> temp = out;
		int i = 0;
		while ((temp.size() > i) && (temp.get(i).indexOf(name) < 0)) {
			i++;
		}
		if (temp.size() <= i) {
			return "";
		}
		int firstIndex = temp.get(i).indexOf(name);
		int lastIndex = temp.get(i).length();
		return out.get(i).substring(firstIndex, lastIndex);
	}
}
